#include "CMAContinuationMPI.h"
#include "CMASearcherMPI.h"
#include "SearcherConfig.h"
#include "ConfigManager.h"
#include "DecoLogger.h"
#ifdef _MPI_IMPLEMENT
#include <mpi.h>

extern double gPassingVariables[100];
extern double (*gEvaluator)(double*, DecoScene*, double*);

CMASearchContinuationMPI::CMASearchContinuationMPI(int rank, int numProcs) : mRank(rank), mNumProcs(numProcs)
{
	miUsedProcs = mNumProcs - 4;
	mpSelectedNodes = new int[miUsedProcs];
}
CMASearchContinuationMPI::~CMASearchContinuationMPI()
{
	delete [] mpSelectedNodes;
}

void CMASearchContinuationMPI::Search()
{
	SelectNodes();
	searchFirstPass();
}

float Reduce(const float* pfVal, const int iCount)
{
	float fRet = 0.0f;
	for(int i = 0; i < iCount; i++)
	{
		fRet *= pfVal[i];
	}
	return fRet;
}

void NodesLog(const char* log)
{
	printf(log);

	FILE* fplog = fopen("NodesSelection.txt", "a");
	fprintf(fplog, log);
	fflush(fplog);
	fclose(fplog);
}

void CMASearchContinuationMPI::SelectNodes()
{
	char logStr[512];
	if(mRank == 0) // Master
	{
		printf("Testing nodes performance.\n");
		MPI_Status mpiStatus;
		vector<NodeTimeTuple> vTuple;
		for(int i = 1; i < mNumProcs; i++)
		{
			int iSrc = i;
			int iTag = i;
			float fResult;
			MPI_Recv(&fResult, 1, MPI_FLOAT, iSrc, iTag, MPI_COMM_WORLD, &mpiStatus);
			sprintf(logStr, "Received response from %dth process: %f\n", iSrc, fResult);
			NodesLog(logStr);

			vTuple.push_back(NodeTimeTuple(i, fResult));
		}
		sort(vTuple.begin(), vTuple.end());

		for(int i = 0; i < miUsedProcs; i++)
		{
			mpSelectedNodes[i] = vTuple[i].iNode;
			sprintf(logStr, "Selected nodes %d used %f.\n", vTuple[i].iNode, vTuple[i].fTime);
			NodesLog(logStr);
		}
	}
	else // Worker
	{
		float afVal[20];
		float afArray[500000];
		for(int i = 0; i < 20; i++)
		{
			afVal[i] = i;
		}

		float fTemp = 0.0f;
		DecoTimer timer;
		timer.startTimer();
		for(int i = 0; i < 5000000; i++)
		{
			fTemp += Reduce(afVal, 20);

			int iAdd = i % 500000;
			int iRow = iAdd / 100;
			int iCol = iAdd % 100;
			int iScb = iCol * 5000 + iRow;
			afArray[iScb] = i * fTemp;
		}
		timer.pauseTimer();

		float fRet = timer.getCurrentTime();
		MPI_Send(&fRet, 1, MPI_FLOAT, 0, mRank, MPI_COMM_WORLD);
	}
}

void CMASearchContinuationMPI::searchFirstPass()
{
	const SearcherInfo& info = DecoConfig::GetSingleton()->GetSearcherInfo();

	int searchDim = static_cast<int>(info.mJointBounds.size());
	printf("Search dimension: %d\n", searchDim);

	double* minBoundary = new double[searchDim];
	double* maxBoundary = new double[searchDim];

	getBoundaryFirstPass(minBoundary, maxBoundary, searchDim);
	int numParamAssigned = static_cast<int>(info.mJointParams.size());
	if (numParamAssigned >= searchDim)
	{
		printf("All the parameters are already assgined, no search needed\n");
		(*DecoLogger::GetSingleton()) << "All the parameters are already assgined, no search needed\n";
		delete[] minBoundary;
		delete[] maxBoundary;
		return;
	}
	CMASearcherMPI searcher(searchDim, numParamAssigned);
	gEvaluator = &Evaluator;
	searcher.Search(&minBoundary[numParamAssigned], &maxBoundary[numParamAssigned], gPassingVariables, 100, mRank, miUsedProcs, mpSelectedNodes);
	delete[] minBoundary;
	delete[] maxBoundary;

}

void CMASearchContinuationMPI::searchSecondPass()
{
	const int searchDim = 12;

	double* minBoundary = new double[searchDim];
	double* maxBoundary = new double[searchDim];

	minBoundary[0] = 0.0;
	minBoundary[1] = 0.25;
	minBoundary[2] = 0.5;
	minBoundary[3] = 0.75;

	maxBoundary[0] = 0.25;
	maxBoundary[1] = 0.5;
	maxBoundary[2] = 0.75;
	maxBoundary[3] = 1.0;

	minBoundary[4] = 0.0;
	minBoundary[5] = 0.25;
	minBoundary[6] = 0.5;
	minBoundary[7] = 0.75;

	maxBoundary[4] = 0.25;
	maxBoundary[5] = 0.5;
	maxBoundary[6] = 0.75;
	maxBoundary[7] = 1.0;

	minBoundary[8] = 0.0;
	minBoundary[9] = 0.25;
	minBoundary[10] = 0.5;
	minBoundary[11] = 0.75;

	maxBoundary[8] = 0.25;
	maxBoundary[9] = 0.5;
	maxBoundary[10] = 0.75;
	maxBoundary[11] = 1.0;

	gEvaluator = &Evaluator2;

	CMASearcherMPI searcher(searchDim, 0);
	searcher.Search(minBoundary, maxBoundary, gPassingVariables, 10000, mRank, miUsedProcs, mpSelectedNodes);

	delete[] minBoundary;
	delete[] maxBoundary;
}

#endif
